package com.lzh.redis.config;

import com.lzh.redis.properties.RedissonProperties;
import org.apache.commons.lang.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhehen.lu
 * @date 2025/9/6 11:26
 */
@EnableConfigurationProperties({RedissonProperties.class})
public class RedissonConfig {
    private static String threadPrefix = "redisson-topic";
    @Autowired
    private RedissonProperties redissonProperties;

    public RedissonConfig() {
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(
            prefix = "spring.redisson",
            name = {"enable"},
            havingValue = "true"
    )
    public RedissonClient redissonClient(RedisProperties redisProperties) {
        CustomizableThreadFactory customizableThreadFactory = new CustomizableThreadFactory(threadPrefix);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors() << 1, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque(200), customizableThreadFactory);
        Config config = new Config();
        config.setNettyThreads(Runtime.getRuntime().availableProcessors() << 1).setExecutor(threadPoolExecutor);
        if (Objects.nonNull(redisProperties.getCluster())) {
            RedisProperties.Cluster cluster = redisProperties.getCluster();
            List<String> nodeAddressList = (List)cluster.getNodes().stream().map((nodeAddress) -> {
                return "redis://" + nodeAddress;
            }).collect(Collectors.toList());
            ((ClusterServersConfig)((ClusterServersConfig)((ClusterServersConfig)config.useClusterServers().addNodeAddress((String[])nodeAddressList.stream().toArray((x$0) -> {
                return new String[x$0];
            })).setPassword(redisProperties.getPassword())).setTimeout(this.redissonProperties.getTimeout())).setRetryAttempts(this.redissonProperties.getRetryAttempts())).setRetryInterval(this.redissonProperties.getRetryInterval());
            if (StringUtils.isNotEmpty(redisProperties.getPassword())) {
                config.useClusterServers().setPassword(redisProperties.getPassword());
            }
        } else if (Objects.nonNull(redisProperties.getSentinel())) {
            RedisProperties.Sentinel sentinel = redisProperties.getSentinel();
            ((SingleServerConfig)((SingleServerConfig)config.useSingleServer().setAddress(sentinel.getMaster()).setTimeout(this.redissonProperties.getTimeout())).setDatabase(redisProperties.getDatabase()).setRetryAttempts(this.redissonProperties.getRetryAttempts())).setRetryInterval(this.redissonProperties.getRetryInterval());
            if (StringUtils.isNotEmpty(redisProperties.getPassword())) {
                config.useSingleServer().setPassword(redisProperties.getPassword());
            }
        } else {
            ((SingleServerConfig)((SingleServerConfig)config.useSingleServer().setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort()).setTimeout(this.redissonProperties.getTimeout())).setDatabase(redisProperties.getDatabase()).setRetryAttempts(this.redissonProperties.getRetryAttempts())).setRetryInterval(this.redissonProperties.getRetryInterval());
            if (StringUtils.isNotEmpty(redisProperties.getPassword())) {
                config.useSingleServer().setPassword(redisProperties.getPassword());
            }
        }

        return Redisson.create(config);
    }
}
